package org.dromara.patrol.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.ObjectUtil;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.TreeBuildUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.patrol.domain.PatrolTemplate;
import org.dromara.patrol.domain.PatrolTemplateNode;
import org.dromara.patrol.domain.bo.PatrolTemplateNodeBo;
import org.dromara.patrol.domain.vo.PatrolTemplateNodeVo;
import org.dromara.patrol.mapper.PatrolTemplateMapper;
import org.dromara.patrol.mapper.PatrolTemplateNodeMapper;
import org.dromara.patrol.service.IPatrolTemplateNodeService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

/**
 * 巡店管理-巡店模板分类（评分项）配置Service业务层处理
 *
 * @author LionLi
 * @date 2024-03-25
 */
@RequiredArgsConstructor
@Service
public class PatrolTemplateNodeServiceImpl implements IPatrolTemplateNodeService {

    private final PatrolTemplateNodeMapper baseMapper;

    private final PatrolTemplateMapper patrolTemplateMapper;

    /**
     * 查询巡店管理-巡店模板分类（评分项）配置
     */
    @Override
    public PatrolTemplateNodeVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询巡店管理-巡店模板分类（评分项）配置列表
     */
    @Override
    public TableDataInfo<PatrolTemplateNodeVo> queryPageList(PatrolTemplateNodeBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<PatrolTemplateNode> lqw = buildQueryWrapper(bo);
        Page<PatrolTemplateNodeVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询巡店管理-巡店模板分类（评分项）配置列表
     */
    @Override
    public List<PatrolTemplateNodeVo> queryList(PatrolTemplateNodeBo bo) {
        LambdaQueryWrapper<PatrolTemplateNode> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<PatrolTemplateNode> buildQueryWrapper(PatrolTemplateNodeBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<PatrolTemplateNode> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getParentId() != null, PatrolTemplateNode::getParentId, bo.getParentId());
        lqw.eq(bo.getTemplateId() != null, PatrolTemplateNode::getTemplateId, bo.getTemplateId());
        lqw.like(StringUtils.isNotBlank(bo.getName()), PatrolTemplateNode::getName, bo.getName());
        lqw.eq(bo.getScore() != null, PatrolTemplateNode::getScore, bo.getScore());
        lqw.eq(bo.getProcessTime() != null, PatrolTemplateNode::getProcessTime, bo.getProcessTime());
        lqw.eq(StringUtils.isNotBlank(bo.getTips()), PatrolTemplateNode::getTips, bo.getTips());
        lqw.eq(StringUtils.isNotBlank(bo.getSelfCheckRemark()), PatrolTemplateNode::getSelfCheckRemark, bo.getSelfCheckRemark());
        lqw.eq(StringUtils.isNotBlank(bo.getIsItem()), PatrolTemplateNode::getIsItem, bo.getIsItem());
        lqw.eq(StringUtils.isNotBlank(bo.getRectifyImage()), PatrolTemplateNode::getRectifyImage, bo.getRectifyImage());
        lqw.eq(StringUtils.isNotBlank(bo.getStandardPictures()), PatrolTemplateNode::getStandardPictures, bo.getStandardPictures());
        lqw.eq(StringUtils.isNotBlank(bo.getNodeScoreType()), PatrolTemplateNode::getNodeScoreType, bo.getNodeScoreType());
        lqw.eq(StringUtils.isNotBlank(bo.getDetailRegulations()), PatrolTemplateNode::getDetailRegulations, bo.getDetailRegulations());
        lqw.eq(StringUtils.isNotBlank(bo.getAllowExceedLimit()), PatrolTemplateNode::getAllowExceedLimit, bo.getAllowExceedLimit());
        lqw.eq(StringUtils.isNotBlank(bo.getScoringRuleApplyScope()), PatrolTemplateNode::getScoringRuleApplyScope, bo.getScoringRuleApplyScope());
        lqw.eq(bo.getApplyClassificationId() != null, PatrolTemplateNode::getApplyClassificationId, bo.getApplyClassificationId());
        lqw.eq(StringUtils.isNotBlank(bo.getImportance()), PatrolTemplateNode::getImportance, bo.getImportance());
        lqw.eq(StringUtils.isNotBlank(bo.getRelDutyPerson()), PatrolTemplateNode::getRelDutyPerson, bo.getRelDutyPerson());
        lqw.eq(StringUtils.isNotBlank(bo.getPatrolStoreImage()), PatrolTemplateNode::getPatrolStoreImage, bo.getPatrolStoreImage());
        lqw.eq(StringUtils.isNotBlank(bo.getLabel()), PatrolTemplateNode::getLabel, bo.getLabel());
        return lqw;
    }

    /**
     * 新增巡店管理-巡店模板分类（评分项）配置
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertByBo(PatrolTemplateNodeBo bo) {
        PatrolTemplateNode patrolTemplateNode = MapstructUtils.convert(bo, PatrolTemplateNode.class);
        try {
            Boolean add = baseMapper.insert(patrolTemplateNode) > 0;
            if (add) {
                buildTemplateNodeScore(patrolTemplateNode);
                //修改评分项数量
                updateTemplateItemNum(patrolTemplateNode.getTemplateId());
            }
            return add;
        } catch (Exception e) {
            throw new ServiceException("更新节点信息并计算得分时发生错误");
        }
    }

    /**
     * 构件父类分数
     * @param add
     */
    private void buildTemplateNodeScore(PatrolTemplateNode add) {
        if (add == null || add.getParentId() == null || !calculateAndUpdateScore(add)) {
            return;
        }
        PatrolTemplateNode parent = baseMapper.selectById(add.getParentId());
        if (ObjectUtil.isNull(parent)) {
            return;
        }
        this.buildTemplateNodeScore(parent);
    }

    private boolean calculateAndUpdateScore(PatrolTemplateNode parentNode) {
        LambdaQueryWrapper<PatrolTemplateNode> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PatrolTemplateNode::getParentId,
                parentNode.getParentId());

        List<PatrolTemplateNodeVo> patrolTemplateNodeVos = baseMapper.selectVoList(queryWrapper);
        BigDecimal score = BigDecimal.ZERO;
        for (PatrolTemplateNodeVo patrolTemplateNodeVo : patrolTemplateNodeVos) {
            BigDecimal nodeScore = patrolTemplateNodeVo.getScore();
            if (nodeScore != null) {
                score = score.add(nodeScore);
            }
        }

        PatrolTemplateNode updateNode = new PatrolTemplateNode();
        updateNode.setId(parentNode.getParentId());
        updateNode.setScore(score);
        int rowsAffected = baseMapper.updateById(updateNode);
        return rowsAffected > 0;
    }

    /**
     * 修改巡店管理-巡店模板分类（评分项）配置
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByBo(PatrolTemplateNodeBo bo) {
        PatrolTemplateNode update = MapstructUtils.convert(bo, PatrolTemplateNode.class);
        // 合并更新与计算得分的操作，尽量在一个事务内完成
        try {
            Boolean updated = baseMapper.updateById(update) > 0;
            if (updated) {
                buildTemplateNodeScore(update);
            }
            return updated;
        } catch (Exception e) {
            throw new ServiceException("更新节点信息并计算得分时发生错误");
        }
    }



    /**
     * 批量删除巡店管理-巡店模板分类（评分项）配置
     */
    @Override
    public Boolean deleteWithValidById(Long id) {
        try {
            PatrolTemplateNode patrolTemplateNode = baseMapper.selectById(id);
            Boolean delete = baseMapper.deleteById(id) > 0;
            if (delete) {
                buildTemplateNodeScore(patrolTemplateNode);
                //修改评分项数量
                updateTemplateItemNum(patrolTemplateNode.getTemplateId());
            }
            return delete;
        } catch (Exception e) {
            throw new ServiceException("更新节点信息并计算得分时发生错误");
        }
    }

    private void updateTemplateItemNum(Long templateId) {
        PatrolTemplate patrolTemplate = patrolTemplateMapper.selectById(templateId);
        if (patrolTemplate == null) {
            // 若模板不存在，可以根据实际情况选择抛出异常或忽略
            throw new ServiceException("模板ID对应的数据不存在");
        }
        List<PatrolTemplateNodeVo> patrolTemplateNodeVos = baseMapper.selectVoList(new LambdaQueryWrapper<PatrolTemplateNode>().eq(
                PatrolTemplateNode::getTemplateId, templateId).eq(PatrolTemplateNode::getIsItem,0));
        // 只有当节点数量发生变化时才进行更新操作，避免无效更新
        if ( patrolTemplate.getItemNum() != patrolTemplateNodeVos.size()) {
            patrolTemplate.setTemplateId(templateId);
            patrolTemplate.setItemNum((long) patrolTemplateNodeVos.size());
            patrolTemplateMapper.updateById(patrolTemplate);
        }
    }

    /**
     * 查询巡店管理-巡店模板分类（评分项）配置，树形结构的查询
     *
     * @param bo
     * @return
     */
    @Override
    public List<Tree<Long>> tree(PatrolTemplateNodeBo bo) {
        //查询所有的分类
        LambdaQueryWrapper<PatrolTemplateNode> lqw = buildQueryWrapper(bo);
        List<PatrolTemplateNodeVo> sysAreas = baseMapper.selectVoList(lqw);
        if (CollUtil.isEmpty(sysAreas)) {
            return CollUtil.newArrayList();
        }
        return buildTemplateTreeSelect(sysAreas);
    }


    /**
     * 构建前端所需要下拉树结构
     *
     * @param templates 模版分类列表
     * @return 下拉树结构列表
     */
    @Override
    public List<Tree<Long>> buildTemplateTreeSelect(List<PatrolTemplateNodeVo> templates) {
        //先组装sysAreaVO,在对sysAreaVo进行递归改成树结构
        return TreeBuildUtils.build(templates, (template, node) -> {
            node.setId(template.getId());
            node.setParentId(template.getParentId());
//            node.setWeight(template.getOrderNum());	//排序权重
            node.setName(template.getName());
            // 如果不想一个个putExtra，可以直接Bean 转 Map 遍历赋值
            Map<String, Object> map = BeanUtil.beanToMap(template);
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                node.putExtra(entry.getKey() ,entry.getValue());
            }

        });
    }

    /**
     * 判断是否包含子节点
     *
     * @param id
     * @return
     */
    @Override
    public boolean hasChildByNodeId(Long id) {
        return baseMapper.exists(new LambdaQueryWrapper<PatrolTemplateNode>()
                .eq(PatrolTemplateNode::getParentId, id));
    }
}
